#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define N 128

// 01-socket 192.168.1.2  8000
// argv[0]   arv[1]       argv[2]
int main(int argc, char const *argv[])
{

    int sockfd, ret, newsockfd;
    struct sockaddr_in myaddr, client_addr;
    socklen_t addrlen;
    char buf[N] = {0};

    if (argc != 3)
    {
        fprintf(stderr, "错误:运行程序时请带入参数(./09-tcp_fork_server ip port)\n");
        exit(-1);
    }

    // 创建一个socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket");
        exit(-1);
    }
    printf("sockfd=%d\n", sockfd);

    memset(&myaddr, 0, sizeof(myaddr));           // 清空结构体
    memset(&client_addr, 0, sizeof(client_addr)); // 清空结构体
    myaddr.sin_family = AF_INET;                  // 什么类型的通信
    myaddr.sin_port = htons(atoi(argv[2]));       // 设置socket 的固定端口
    myaddr.sin_addr.s_addr = inet_addr(argv[1]);  // 把字符串ip转换成网络二进制的ip地址

    ret = bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr));
    if (ret < 0)
    {
        perror("bind");
        exit(-1);
    }

    ret = listen(sockfd, 10);
    if (ret < 0)
    {
        perror("listen");
        exit(-1);
    }

    // system("netstat -ant");
    addrlen = sizeof(client_addr); //这个赋值如果缺少, 可能会引发程序错误

    while (1)
    {
        newsockfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen); // 接收客户端tcp连接请求

        if (fork() == 0)
        {
            while (1)
            {
                ret = recv(newsockfd, buf, N, 0); // 接收客户端发来的数据
                if (ret < 0)
                {
                    perror("read");
                    exit(-1);
                }

                if (strncmp(buf, "quit", 4) == 0)
                    break;

                printf("%s & %d said :%s\n", inet_ntoa(client_addr.sin_addr),
                       ntohs(client_addr.sin_port), buf);

                strcpy(buf, "server is recevied!");

                ret = send(newsockfd, buf, N, 0); // 发送给客户端
                if (ret < 0)
                {
                    perror("send");
                    exit(-1);
                }
            }
            close(newsockfd);
            exit(0);
        }
        close(newsockfd); // 关闭客户端连接
    }
    close(sockfd);

    return 0;
}
